﻿using Newtonsoft.Json;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using static ATEGo.CmdField;

namespace ATEGo
{
    //———————————————————————【执行流程】————————————————————————
    public partial class Executor
    {
        InitialExecutor Initial;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Path_TestTree">测试树json文件路径</param>
        /// <param name="form1">展示窗体</param>
        /// <param name="ThreadIndex">线程几在执行</param>
        public Executor(IExecutorForm form1, InitialExecutor InitialExecutor, int ThreadIndex)
        {
            this.Initial = InitialExecutor;
            this.This_Form = form1;
            this.ThreadIndex = ThreadIndex;
        }
        //———————————————————————目前正在执行的变量Running2————————————————————————
        /// <summary>
        /// 目前执行的CmdTag
        /// </summary>
        private CmdTag Running_CmdTag { get; set; } = new CmdTag();
        /// <summary>
        /// 目前执行的默认CmdTag
        /// </summary>
        private CmdTag Get_CmdTag_Default(string cmdSuits)
        {
            return Initial.Group_CmdSuits[cmdSuits].Default_cmdTag;
        }
        /// <summary>
        /// 目前执行的cmd
        /// </summary>
        private CmdDict Running_Cmd { get; set; }
        [ThreadStatic]
        /// <summary>
        /// 目前正在执行第几条命令了？
        /// </summary>
        public int CountCmd = 0;
        /// <summary>
        /// 待执行的下一条命令
        /// </summary>
        private CmdDict Next_Cmd { get; set; }
        /// <summary>
        /// 目前执行的任务
        /// </summary>
        private TaskCompletionSource<bool> Running_TCS { get; set; } = new TaskCompletionSource<bool>();
        /// <summary>
        /// 暂停
        /// </summary>
        private ManualResetEvent MRE = new ManualResetEvent(true);
        /// <summary>
        /// 取消异步
        /// </summary>
        private CancellationTokenSource Running_CTS { get; set; } = new CancellationTokenSource();
        /// <summary>
        /// 结果表
        /// </summary>
        public ResultTable Running_ResultTB { get; set; } = new ResultTable();

        //———————————————————————【执行流程】————————————————————————
        /// <summary>
        /// 执行窗体的开始动作
        /// </summary>
        private void FormStartAction()
        {
            WriteFlow_Head1("开始执行!");
            Action act = () =>
            {
                Action_Start?.Invoke();
            };
            This_Form.Invoke(act);
        }
        /// <summary>
        /// 执行窗体的结束动作
        /// </summary>
        private void FormEndAction()
        {
            WriteFlow_Head1("结束执行!");
            Action act = () =>
            {
                Action_End?.Invoke();
            };
            This_Form.Invoke(act);
        }
        /// <summary>
        /// 开始执行前的动作
        /// </summary>
        private void BeforeStart()
        {
            IsStop = false;
            //结果表格重置
            Running_ResultTB.Reset();
            //注册取消
            Running_CTS = new CancellationTokenSource();
            Running_CTS.Token.Register(() =>
            {
                MsgShow.OK($"线程{ThreadIndex+1}-用户已取消！", $"线程{ThreadIndex+1}");
                CheckAndStop();
            });
        }
        /// <summary>
        /// 开始执行
        /// </summary>
        public void Start(string FlowName)
        {
            try
            {
                //开始
                Task.Run(async () =>
                {
                    BeforeStart();
                    //窗体开始动作
                    FormStartAction();
                    WriteFlow_Head2($"执行流程 [{FlowName}]");
                    //赋值执行的变量
                    var res = P2_GetRunningParams(FlowName);
                    if (!res)
                    {
                        return;
                    }
                    //开始执行
                    await ExcFlow(FlowName);
                    //窗体结束动作
                    FormEndAction();
                });
            }
            catch (Exception e)
            {
                MsgShow.Error(This_Form, e.Message, $"线程{ThreadIndex + 1}");
                //窗体结束动作
                FormEndAction();
            }
        }
        /// <summary>
        /// 暂停执行
        /// </summary>
        public void Pause()
        {
            MRE.Reset();
        }
        /// <summary>
        /// 继续执行
        /// </summary>
        public void GoOn()
        {
            MRE.Set();
        }

        /// <summary>
        /// 执行一个流程，里面有多个CmdTag
        /// </summary>
        /// <param name="FlowName"></param>
        private async Task<bool> ExcFlow(string FlowName)
        {
            //设置progress的初值
            Pb_InitialValue(Running_Flows.Count);
            //设置执行了几条命令
            CountCmd = 0;
            //如果是串行执行
            if (Running_OrderItem.executeWay.Trim().ToLower() == "sequence")
            {
                //按流程指定的顺序 执行CmdTag
                foreach (var item in Running_Flows)
                {
                    //将命令集地址名称[0]和cmdtag[1]拆分出来
                    var tt = SplitCmdTag(item.Trim());
                    //注释则跳过
                    if (CmdIsAnn(tt[1]))
                    {
                        Pb_Add();
                        continue;
                    }
                    //执行cmdTag
                    bool res = await ExcCmdTag(tt[0], tt[1]);
                    if (res)
                    {
                        //返回正确，progress增加
                        Pb_Add();
                    }
                    else
                    {
                        //返回错误，则停止执行
                        Pb_Error();
                        return false;
                    }
                }
                //执行成功，progress呈现最后状态
                Pb_End();
                return true;
            }
            else if (Running_OrderItem.executeWay.Trim().ToLower() == "concurrent")
            {
                MsgShow.Error(This_Form, "程序暂未实现", $"线程{ThreadIndex + 1}");
            }
            else
            {
                MsgShow.Error(This_Form, "程序暂未实现", $"线程{ThreadIndex + 1}");
            }
            return true;
        }

        /// <summary>
        /// 执行某一个CmdTag
        /// </summary>
        /// <param name="cmdTagName"></param>
        private async Task<bool> ExcCmdTag(string cmdSuits,string cmdTagName)
        {
            //找到CmdSuits里面对应的CmdTag
            var t = Initial.Group_CmdSuits[cmdSuits];
            Running_CmdTag = Initial.Group_CmdSuits[cmdSuits][cmdTagName];
            if (Running_CmdTag is null)
            {
                MsgShow.Error(This_Form, $"未在{cmdSuits}命令集中，找到{cmdTagName}命令！", $"线程{ThreadIndex + 1}");
                return false;
            }
            //cmdTag名称中有#表示有变量，拆出来放入params_incmd中去
            if (cmdTagName.Contains("#"))
            {
                var temp = cmdTagName.Split(new string[] {"#"},StringSplitOptions.RemoveEmptyEntries);
                for (int i = 1; i< temp.Length;i++)
                {
                    Params_InCmd["%"+i.ToString()] = temp[i];
                }
            }
            //if判断
            if (!string.IsNullOrWhiteSpace(Running_CmdTag.@if))
            {
                var sentence = Running_CmdTag.@if.Trim().ReplaceParas(this);
                //执行语句
                var r = CSharpExecute.EvalExpression(sentence);
                //执行结果
                if (!Convert.ToBoolean(r))
                {
                    WriteFlow_Content($"if执行结果为{r}，跳过命令集{cmdTagName}");
                    return true;
                }
                else
                {
                    WriteFlow_Content($"if匹配，准备执行命令集{cmdTagName}");
                }
            }
            //loop循环设置
            int[] loops = new int[3] { 0, 1, 1 };
            string loops_if = "";
            if (!string.IsNullOrWhiteSpace(Running_CmdTag.loop))
            {
                if (Regex.IsMatch(Running_CmdTag.loop.Trim(), "[0-9]*\\s*:\\s*[0-9]*\\s*:\\s*[0-9]*"))
                {
                    var pp = Running_CmdTag.loop.Trim().Split(new string[] { ":" }, StringSplitOptions.None);
                    loops[0] = Convert.ToInt32(pp[0]);
                    loops[1] = Convert.ToInt32(pp[1]);
                    loops[2] = Convert.ToInt32(pp[2]);
                }
                else if(Regex.IsMatch(Running_CmdTag.loop.Trim(), "[0-9]*"))
                {
                    loops[1] = Convert.ToInt32(Running_CmdTag.loop);
                }
                else if (Regex.IsMatch(Running_CmdTag.loop.Trim(), "[0-9]*\\s*:.*:\\s*[0-9]*"))
                {
                    var pp = Running_CmdTag.loop.Trim().Split(new string[] { ":" }, StringSplitOptions.None);
                    loops[0] = Convert.ToInt32(pp[0]);
                    loops_if = pp[1].Trim().ReplaceParas(this);
                    loops[2] = Convert.ToInt32(pp[2]);
                }
            }
            for (int k = loops[0]; k < loops[1] ; k += loops[2])
            {
                //检查loops_if
                if (!string.IsNullOrWhiteSpace(loops_if))
                {
                    if (!Convert.ToBoolean(CSharpExecute.EvalExpression(loops_if)))
                    {
                        return true;
                    }
                }
                Params_InCmd["%t"] = k.ToString();
                bool result = false;

                //按序执行该Cmdtag里面的cmd
                for (int i = 0; i < Running_CmdTag.Count; i++)
                {
                    //本条命令
                    var thisTimeCmd = Running_CmdTag[i];
                    //写结果表
                    Running_ResultTB.AddALine();
                    Running_ResultTB.LastRow[ResultDTColumns.CmdSuits.ToString()] = cmdSuits;
                    Running_ResultTB.LastRow[ResultDTColumns.CmdTag.ToString()] = cmdTagName;
                    Running_ResultTB.LastRow[ResultDTColumns.CmdIndex.ToString()] = i;
                    //告诉该cmd默认的cmdTag是哪个
                    thisTimeCmd.Default_CmdTag = Get_CmdTag_Default(cmdSuits);

                    //检查if
                    if (!string.IsNullOrWhiteSpace(thisTimeCmd["if"]))
                    {
                        var sentence = thisTimeCmd["if"].Trim().ReplaceParas(this);
                        //执行语句
                        var r = CSharpExecute.EvalExpression(sentence);
                        //执行结果
                        if (!Convert.ToBoolean(r))
                        {
                            WriteFlow_Content($"if执行结果为{r}，跳过命令：{thisTimeCmd[cmd]}");
                            continue;
                        }
                        else
                        {
                            WriteFlow_Content($"if匹配，准备执行命令...");
                        }
                    }
                    //检查ifLast，不匹配不执行该条命令
                    if (!string.IsNullOrWhiteSpace(thisTimeCmd[ifLast]))
                    {
                        var lastRes = thisTimeCmd[ifLast].JsonIfLast();
                        if (lastRes != result)//result残存上一次的结果
                        {
                            WriteFlow_Content($"{ifLast}要求上次结果为{lastRes}，实际为{result}，跳过命令：{thisTimeCmd[cmd]}");
                            continue;
                        }
                        else
                        {
                            WriteFlow_Content($"{ifLast}匹配，准备执行命令...");
                        }
                    }
                    //检查是否符合ifReg的匹配，不匹配不执行该条命令,此时Running_Cmd_Buffer还残留着上一次的回显
                    var lastcmd = Running_Cmd_Buffer.ToString();
                    if (!string.IsNullOrWhiteSpace(lastcmd) && !string.IsNullOrWhiteSpace(thisTimeCmd[ifReg]))
                    {
                        if (!Regex.IsMatch(lastcmd, thisTimeCmd[ifReg].ReplaceParas(this, true)))
                        {
                            WriteFlow_Content($"{ifReg}不匹配，跳过命令：{thisTimeCmd[cmd]}");
                            continue;
                        }
                        else
                        {
                            WriteFlow_Content($"{ifReg}匹配，准备执行命令...");
                        }
                    }
                    //指向下一条命令
                    if (i < Running_CmdTag.Count - 1)
                    {
                        Next_Cmd = Running_CmdTag[i + 1];
                        Next_Cmd.Default_CmdTag = Get_CmdTag_Default(cmdSuits);
                    }
                    else//最后一条命令的下一个指向null
                    {
                        Next_Cmd = null;
                    }
                    //执行某一条语句
                    result = await ExcCmd(cmdTagName, thisTimeCmd);
                    //如果执行不成功，并且要求重试
                    if (!result && thisTimeCmd["failed?Retry:GoOn"].JsonFailedRetryGoon())
                    {
                        //进行重试
                        int j = 0;
                        for (; j < thisTimeCmd[retryTimes].JsonToInt32(); j++)
                        {
                            WriteFlow_Content($"第{j + 1}次重试");
                            int p_retryInterval = thisTimeCmd[retryInterval].TimeToMS();
                            //重试间隔
                            if (IsPrintDebugInfo)
                            {
                                WriteFlow_Waiting($"{p_retryInterval}毫秒，重试间隔");
                            }
                            await Task.Delay(p_retryInterval, Running_CTS.Token);
                            //是否停止
                            if (CheckAndStop())
                            {
                                return false;
                            }
                            //执行重试
                            var retryResult = await ExcCmd(cmdTagName, thisTimeCmd);
                            //执行成功则停止重试
                            if (retryResult)
                            {
                                break;
                            }
                        }
                        //重试完成，还是失败。程序停止执行。
                        if (j == thisTimeCmd[retryTimes].JsonToInt32())
                        {
                            //最终才展示失败原因
                            if (!string.IsNullOrWhiteSpace(thisTimeCmd[failedMsgShow]))
                            {
                                MsgShow.Error(This_Form, ReplaceCmdParas(thisTimeCmd[failedMsgShow].Trim()), $"线程{ThreadIndex + 1}");
                            }
                            return false;
                        }
                    }

                    int p_interval = Running_Cmd[interval].TimeToMS();
                    //本次执行完毕后，命令间隔。如果已经是暂停了，则不再暂停了
                    if (!thisTimeCmd[cmd].Contains("#PAUSE#"))
                    {
                        if (IsPrintDebugInfo)
                        {
                            WriteFlow_Waiting($"{p_interval}毫秒，命令间隔");
                        }
                        await Task.Delay(p_interval, Running_CTS.Token);
                    }
                    //是否停止
                    if (CheckAndStop())
                    {
                        return false;
                    }
                }
            }
            
            return true;
        }

        /// <summary>
        /// 具体执行某一条语句
        /// </summary>
        /// <param name="cmdDict"></param>
        private async Task<bool> ExcCmd(string cmdTagName, CmdDict cmdDict)
        {
            MRE.WaitOne();
            //初始化执行语句的变量
            bool result;
            CountCmd++;
            //正在执行的cmd
            Running_Cmd = cmdDict;
            //保存上一次的cmd的回显
            Last_Cmd_Buffer = Running_Cmd_Buffer.ToString();
            Running_Cmd_Buffer.Clear();
            Running_TCS = new TaskCompletionSource<bool>();
            //清空默认变量
            Params_GrabResult.Clear();
            //执行外部事件
            Action act = () =>
            {
                Action_ExeNextCmd?.Invoke(CountCmd);
            };
            This_Form.Invoke(act);

            //获取到具体的指令
            var cmd = cmdDict["cmd"].Trim();
            //将cmd里面的变量替换掉
            cmd = cmd.ReplaceParas(this);
            //写结果表
            Running_ResultTB.LastRow[ResultDTColumns.Cmd.ToString()] = cmd;
            WriteFlow_Sperator();
            //1 注释指令，形如"###指令"
            if (CmdIsAnn(cmd))
            {
                WriteFlow_Zhushi(cmdTagName, cmd);
                WriteCmd_Cmd(cmdTagName, "###"+cmd);
                //写结果表
                Running_ResultTB.LastRow[ResultDTColumns.Result.ToString()] = "###";
                return true;
            }
            //2 特权指令由C#处理，形如"#特权指令#参数#"
            if (CmdIsSpecial(cmd))
            {
                WriteFlow_SendCmd(cmdTagName, cmd + cmdDict["params"]);
                WriteCmd_Cmd(cmdTagName, cmd);
                WriteCmd(cmdDict["params"]);
                result = await ExecuteSpecialCmd(cmd,cmdDict);
            }
            //3 正常发送命令
            else
            {
                WriteFlow_SendCmd(cmdTagName, cmd);
                WriteCmd_Cmd(cmdTagName, cmd);
                //打开接收回显
                IsReceiveEcho = true;
                //发送给cmd执行命令
                windowsCmd.Excute(cmd);

                //TimeOut开始计时，保证能有时间接收到足够的回显，然后发送下一条命令
                TimerStart();
                //接收结果
                result = await Running_TCS.Task;
                //停下TimeOut，不需要它处理结果
                TimerStop(false);
            }
            //写结果表
            Running_ResultTB.LastRow[ResultDTColumns.Result.ToString()] = ((result==true)?"success":"fail");
            return result;
        }
    }
}
